/**
 * Performance Optimization Utilities
 * 性能优化工具函数
 */

/**
 * 节流函数
 * @param func 要节流的函数
 * @param limit 时间间隔（毫秒）
 */
export function throttle<T extends (...args: any[]) => any>(
  func: T,
  limit: number
): (...args: Parameters<T>) => void {
  let inThrottle: boolean;
  let lastResult: ReturnType<T>;

  return function (this: any, ...args: Parameters<T>): void {
    if (!inThrottle) {
      inThrottle = true;
      lastResult = func.apply(this, args);
      setTimeout(() => (inThrottle = false), limit);
    }
  };
}

/**
 * 防抖函数
 * @param func 要防抖的函数
 * @param delay 延迟时间（毫秒）
 */
export function debounce<T extends (...args: any[]) => any>(
  func: T,
  delay: number
): (...args: Parameters<T>) => void {
  let timeoutId: NodeJS.Timeout;

  return function (this: any, ...args: Parameters<T>): void {
    clearTimeout(timeoutId);
    timeoutId = setTimeout(() => func.apply(this, args), delay);
  };
}

/**
 * 请求动画帧节流
 * 用于优化滚动、拖拽等高频事件
 */
export function rafThrottle<T extends (...args: any[]) => any>(
  func: T
): (...args: Parameters<T>) => void {
  let rafId: number | null = null;

  return function (this: any, ...args: Parameters<T>): void {
    if (rafId === null) {
      rafId = requestAnimationFrame(() => {
        func.apply(this, args);
        rafId = null;
      });
    }
  };
}

/**
 * 延迟加载图片
 * @param imgElements 图片元素数组
 * @param options IntersectionObserver 选项
 */
export function lazyLoadImages(
  imgElements: HTMLImageElement[],
  options?: IntersectionObserverInit
): () => void {
  const imageObserver = new IntersectionObserver((entries) => {
    entries.forEach((entry) => {
      if (entry.isIntersecting) {
        const img = entry.target as HTMLImageElement;
        const src = img.dataset.src;
        if (src) {
          img.src = src;
          img.removeAttribute('data-src');
          imageObserver.unobserve(img);
        }
      }
    });
  }, options);

  imgElements.forEach((img) => imageObserver.observe(img));

  // 返回清理函数
  return () => {
    imgElements.forEach((img) => imageObserver.unobserve(img));
    imageObserver.disconnect();
  };
}

/**
 * 虚拟滚动计算
 * 计算可见范围内的项目
 */
export interface VirtualScrollParams {
  scrollTop: number;
  containerHeight: number;
  itemHeight: number;
  totalItems: number;
  overscan?: number; // 额外渲染的项目数量
}

export interface VirtualScrollResult {
  startIndex: number;
  endIndex: number;
  offsetY: number;
  visibleItems: number;
}

export function calculateVirtualScroll(
  params: VirtualScrollParams
): VirtualScrollResult {
  const { scrollTop, containerHeight, itemHeight, totalItems, overscan = 3 } = params;

  const startIndex = Math.max(0, Math.floor(scrollTop / itemHeight) - overscan);
  const visibleItems = Math.ceil(containerHeight / itemHeight);
  const endIndex = Math.min(
    totalItems - 1,
    startIndex + visibleItems + overscan * 2
  );

  const offsetY = startIndex * itemHeight;

  return {
    startIndex,
    endIndex,
    offsetY,
    visibleItems
  };
}

/**
 * 分块处理大数组
 * 避免阻塞主线程
 */
export async function chunkArray<T>(
  array: T[],
  processor: (item: T, index: number) => void | Promise<void>,
  chunkSize: number = 100
): Promise<void> {
  for (let i = 0; i < array.length; i += chunkSize) {
    const chunk = array.slice(i, i + chunkSize);

    // 处理当前块
    await Promise.all(
      chunk.map((item, chunkIndex) => processor(item, i + chunkIndex))
    );

    // 让出主线程
    await new Promise(resolve => setTimeout(resolve, 0));
  }
}

/**
 * Web Worker 包装器
 * 简化 Web Worker 的使用
 */
export class WorkerPool {
  private workers: Worker[] = [];
  private availableWorkers: Worker[] = [];
  private taskQueue: Array<{
    data: any;
    resolve: (value: any) => void;
    reject: (reason: any) => void;
  }> = [];

  constructor(workerScript: string, poolSize: number = 4) {
    for (let i = 0; i < poolSize; i++) {
      const worker = new Worker(workerScript);
      this.workers.push(worker);
      this.availableWorkers.push(worker);
    }
  }

  execute<T = any>(data: any): Promise<T> {
    return new Promise((resolve, reject) => {
      const worker = this.availableWorkers.pop();

      if (worker) {
        this.runTask(worker, data, resolve, reject);
      } else {
        this.taskQueue.push({ data, resolve, reject });
      }
    });
  }

  private runTask(
    worker: Worker,
    data: any,
    resolve: (value: any) => void,
    reject: (reason: any) => void
  ): void {
    const messageHandler = (e: MessageEvent) => {
      worker.removeEventListener('message', messageHandler);
      worker.removeEventListener('error', errorHandler);

      this.availableWorkers.push(worker);
      resolve(e.data);

      // 处理队列中的下一个任务
      const nextTask = this.taskQueue.shift();
      if (nextTask) {
        this.runTask(
          this.availableWorkers.pop()!,
          nextTask.data,
          nextTask.resolve,
          nextTask.reject
        );
      }
    };

    const errorHandler = (error: ErrorEvent) => {
      worker.removeEventListener('message', messageHandler);
      worker.removeEventListener('error', errorHandler);

      this.availableWorkers.push(worker);
      reject(error);
    };

    worker.addEventListener('message', messageHandler);
    worker.addEventListener('error', errorHandler);
    worker.postMessage(data);
  }

  terminate(): void {
    this.workers.forEach(worker => worker.terminate());
    this.workers = [];
    this.availableWorkers = [];
    this.taskQueue = [];
  }
}

/**
 * 性能监控工具
 */
export class PerformanceMonitor {
  private marks: Map<string, number> = new Map();

  /**
   * 开始性能标记
   */
  mark(name: string): void {
    this.marks.set(name, performance.now());
  }

  /**
   * 测量性能并返回时长
   */
  measure(name: string): number {
    const startTime = this.marks.get(name);
    if (startTime === undefined) {
      console.warn(`Performance mark "${name}" not found`);
      return 0;
    }

    const duration = performance.now() - startTime;
    this.marks.delete(name);

    console.log(`[Performance] ${name}: ${duration.toFixed(2)}ms`);
    return duration;
  }

  /**
   * 清除所有标记
   */
  clear(): void {
    this.marks.clear();
  }
}

/**
 * 内存缓存工具
 */
export class MemoryCache<K = string, V = any> {
  private cache: Map<K, { value: V; expiry: number }> = new Map();
  private maxSize: number;

  constructor(maxSize: number = 100) {
    this.maxSize = maxSize;
  }

  set(key: K, value: V, ttl: number = 300000): void {
    // 如果超过最大大小，删除最旧的项
    if (this.cache.size >= this.maxSize) {
      const firstKey = this.cache.keys().next().value;
      this.cache.delete(firstKey);
    }

    this.cache.set(key, {
      value,
      expiry: Date.now() + ttl
    });
  }

  get(key: K): V | null {
    const item = this.cache.get(key);

    if (!item) {
      return null;
    }

    // 检查是否过期
    if (Date.now() > item.expiry) {
      this.cache.delete(key);
      return null;
    }

    return item.value;
  }

  has(key: K): boolean {
    return this.get(key) !== null;
  }

  delete(key: K): boolean {
    return this.cache.delete(key);
  }

  clear(): void {
    this.cache.clear();
  }

  get size(): number {
    return this.cache.size;
  }
}
